/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.jboss.seam.example.booking.entityquery;

import java.util.Map;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.queryParser.MultiFieldQueryParser;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.hibernate.search.jpa.FullTextEntityManager;
import org.hibernate.search.jpa.FullTextQuery;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.AutoCreate;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.Transactional;
import org.jboss.seam.annotations.security.Restrict;
import org.jboss.seam.example.booking.entity.Hotel;
import org.jboss.seam.faces.FacesMessages;
import org.jboss.seam.framework.EntityQuery;

/**
 *
 * @author RHO
 */
@AutoCreate
@Name("hotelQuery")
@Scope(ScopeType.EVENT)
@Restrict("#{identity.loggedIn}")
public class HotelQuery extends EntityQuery<Hotel> {

    protected String searchPattern;
    protected String searchTerms;
    protected String searchTextView;
    
    private Long resultCount;
    @In
    protected FacesMessages facesMessages;

    public HotelQuery() {
        super();
//        setEjbql("SELECT h FROM Hotel h WHERE LOWER(h.name) "
//                + "LIKE #{hotelQuery.searchPattern}");
        setEjbql("FROM Hotel");
        setMaxResults(10);
        if (getHints() == null) {
            setHints(new java.util.HashMap<String, String>());
        }
        getHints().put("org.hibernate.cacheable", String.valueOf(true));
    }

    @Override
    protected javax.persistence.Query createQuery() {
        joinTransaction();
        FullTextQuery result = getFullTextEntityManager().createFullTextQuery(createSearchQuery(), Hotel.class);
        if (getFirstResult() != null) {
            debug("firstResult " + getFirstResult());
            result.setFirstResult(getFirstResult());
        }
        if (getMaxResults() != null) {
            debug("maxResults " + getMaxResults());
            result.setMaxResults(getMaxResults() + 1);
        }
        if (getHints() != null) {
            for (Map.Entry<String, String> me : getHints().entrySet()) {
                debug("hint: " + me.getKey() + "=" + me.getValue());
                result.setHint(me.getKey(), me.getValue());
            }
        }
        return result;
    }

    protected org.apache.lucene.search.Query createSearchQuery() {
        if ((searchTerms == null) || "".equals(searchTerms.trim())) {
            return createDefQuery();
        }
        try {
            // For Advanced Search
            if (searchTerms.indexOf("+") > 0) {
                MultiFieldQueryParser parser = new MultiFieldQueryParser(new String[]{"name",
                            "city", "country"}, new StandardAnalyzer());
                return parser.parse(searchTerms);
            } // For Quick Search
            else {
                MultiFieldQueryParser parser = new MultiFieldQueryParser(new String[]{"name"},
                        new StandardAnalyzer());
                return parser.parse(searchTerms);
            }
        } catch (ParseException e) {
            facesMessages.addFromResourceBundle("invalid_search_terms", e.getMessage());
            return createDefQuery();
        }
    }

    @Override
    protected javax.persistence.Query createCountQuery() {
        joinTransaction();
        FullTextQuery result = getFullTextEntityManager().createFullTextQuery(createSearchQuery(), Hotel.class);
        return result;
    }

    @Override
    @Transactional
    public Long getResultCount() {
        if (resultCount == null) {
            FullTextQuery resultCountQuery = (FullTextQuery) createCountQuery();
            resultCount = (resultCountQuery == null) ? null : Long.valueOf(resultCountQuery.getResultSize());
        }
        return resultCount;
    }

    public FullTextEntityManager getFullTextEntityManager() {
        return (FullTextEntityManager) getEntityManager();
    }

    protected org.apache.lucene.search.Query createDefQuery() {
        return new MatchAllDocsQuery();
    }

    @Override
    public String getOrder() {
        return "name desc";
    }

    @Override
    public void refresh() {
        super.refresh();
    }

    public void clear() {
        setSearchTerms(null);
    }

    public String getSearchPattern() {
        return searchTerms == null
                ? "%" : '%' + searchTerms.toLowerCase().replace('*', '%') + '%';
    }

    public void setSearchPattern(String searchPattern) {
        this.searchPattern = searchPattern;
    }

    public String getSearchTerms() {
        return searchTerms;
    }

    public String getSearchTextView() {
        return searchTextView;
    }

    public void setSearchTerms(String searchTerms) {
        if ((searchTerms == null) || "".equals(searchTerms)) {
            this.searchTerms = null;
        } else {
            this.searchTerms = searchTerms;
        }
        this.setSearchTextView(searchTerms);
    }

    public void setSearchTextView(String searchTextView) {
        this.searchTextView = searchTextView;
    }
}
